package com.qen.wrapper;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.qen.common.BeetlUtils;
import com.qen.common.SqlHelper;
import com.qen.common.TableInfoHelper;
import com.qen.enums.SqlKeyword;
import com.qen.wrapper.segments.MergeSegments;
import com.qen.wrapper.segments.NormalSegmentList;
import lombok.SneakyThrows;
import org.beetl.sql.annotation.entity.AssignID;
import org.beetl.sql.annotation.entity.AutoID;
import org.beetl.sql.annotation.entity.SeqID;
import org.beetl.sql.clazz.TableDesc;

import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 条件构造抽象类
 *
 * @author licz
 * @since 1.0.0
 */
public abstract class Wrapper<T> implements ISqlSegment {

    /**
     * 实体对象（子类实现）
     *
     * @return 泛型 T
     */
    public abstract T getEntity();

    /**
     * 获取SelectSql
     *
     * @return
     */
    public String getSqlSelect() {
        return null;
    }

    /**
     * 获取Del删除Sql
     *
     * @return
     */
    public String getDeleteSql() {
        return StrUtil.EMPTY;
    }

    /**
     * 获取Del逻辑删除
     *
     * @return
     */
    public String getDeleteLogicSql() {
        return StrUtil.EMPTY;
    }

    /**
     * 获取UnionSql
     *
     * @return
     */
    public String getUnionSql() {
        return StrUtil.EMPTY;
    }

    /**
     * 取WhereSql
     *
     * @return
     */
    public String getWhere() {
        MergeSegments expression = getExpression();
        if (Objects.nonNull(expression)) {
            NormalSegmentList normal = expression.getNormal();
            return normal.getSqlSegment();
        }
        return StrUtil.EMPTY;
    }

    /**
     * Update 用的
     *
     * @return
     */
    public String getSqlSet() {
        return null;
    }

    /**
     * 获取Sql注释
     *
     * @return
     */
    public String getSqlComment() {
        return null;
    }

    /**
     * 用户设置的Sql首部
     *
     * @return
     */
    public String getSqlFirst() {
        return null;
    }

    /**
     * 获取 MergeSegments
     */
    public abstract MergeSegments getExpression();

    public String getAlias() {
        return "";
    }

    /**
     * 获取自定义SQL 简化自定义XML复杂情况
     * <p>
     * 使用方法: `select xxx from table` + ${ew.customSqlSegment}
     * <p>
     * 注意事项:
     * 1. 逻辑删除需要自己拼接条件 (之前自定义也同样)
     * 2. 不支持wrapper中附带实体的情况 (wrapper自带实体会更麻烦)
     * 3. 用法 ${ew.customSqlSegment} (不需要where标签包裹,切记!)
     * 4. ew是wrapper定义别名,不能使用其他的替换
     */
    public String getCustomSqlSegment() {
        MergeSegments expression = getExpression();
        if (Objects.nonNull(expression)) {
            NormalSegmentList normal = expression.getNormal();

            String sqlSegment = getSqlSegment();
            if (StrUtil.isNotBlank(sqlSegment)) {
                if (normal.isEmpty()) {
                    return sqlSegment;
                } else {
                    return SqlKeyword.WHERE.getSqlSegment() + StrUtil.SPACE + sqlSegment;
                }
            }
        }
        return StrUtil.EMPTY;
    }

    /**
     * 查询条件为空(包含entity)
     */
    public boolean isEmptyOfWhere() {
        return isEmptyOfNormal() && isEmptyOfEntity();
    }

    /**
     * 查询条件不为空(包含entity)
     */
    public boolean isNonEmptyOfWhere() {
        return !isEmptyOfWhere();
    }

    public boolean nonEmptyOfWhere() {
        return isNonEmptyOfWhere();
    }

    /**
     * 查询条件为空(不包含entity)
     */
    public boolean isEmptyOfNormal() {
        return CollectionUtil.isEmpty(getExpression().getNormal());
    }

    /**
     * 查询条件为空(不包含entity)
     */
    public boolean isNonEmptyOfNormal() {
        return !isEmptyOfNormal();
    }

    public boolean nonEmptyOfNormal() {
        return isNonEmptyOfNormal();
    }

    /**
     * 深层实体判断属性
     *
     * @return true 不为空
     */
    @SneakyThrows
    public boolean isNonEmptyOfEntity() {
        T entity = getEntity();
        if (entity == null) {
            return false;
        }
        TableDesc tableInfo = TableInfoHelper.getTableInfo(entity.getClass());
        if (tableInfo == null) {
            return false;
        }
        if (CollectionUtil.isNotEmpty(tableInfo.getIdNames())) {
            Object obj = BeetlUtils.getAnnotatedFieldValue(entity, AutoID.class, AssignID.class, SeqID.class);
            return Objects.nonNull(obj);
        }
        return false;
    }

    /**
     * 深层实体判断属性
     *
     * @return true 为空
     */
    public boolean isEmptyOfEntity() {
        return !isNonEmptyOfEntity();
    }

    /**
     * 获取格式化后的执行sql
     *
     * @return sql
     * @since 1.0.0
     */
    public String getTargetSql() {
//        return getSqlSegment().replaceAll("#\\{.+?}", "?");
        return getSqlSegment();
    }

    /**
     * 条件清空
     *
     * @since 1.0.0
     */
    abstract public void clear();

    /**
     * 取包装的参数
     *
     * @return
     */
    abstract public Map<String, Object> getParam();

    abstract public String getFrom();

    abstract public Class<T> getEntityClass();

    public boolean isResultMapCollection() {
        return false;
    }

    /**
     * 链式调用 等效于MP mapper的 selectCount()
     * <p>
     * 构造方法必须传 class 或 entity 否则会报错 <br />
     * new MPJLambdaWrapper(User.class)<br />
     * JoinWrappers.lambda(User.class)<br />
     */
    public Long count() {
        return SqlHelper.execute(getEntityClass(), dao -> dao.selectJoinCount(this));
    }

    /**
     * 链式调用 等效于 selectOne
     * <p>
     * 构造方法必须传 class 或 entity 否则会报错<br />
     * new MPJLambdaWrapper(User.class)<br />
     * JoinWrappers.lambda(User.class)<br />
     */
    public T one() {
        return SqlHelper.execute(getEntityClass(), dao -> dao.selectJoinOne(getEntityClass(), this));
    }

    /**
     * 链式调用 等效于 selectJoinOne
     * <p>
     * 构造方法必须传 class 或 entity 否则会报错<br />
     * new MPJLambdaWrapper(User.class)<br />
     * JoinWrappers.lambda(User.class)<br />
     */
    public <R> R one(Class<R> resultType) {
        return SqlHelper.execute(getEntityClass(), dao -> dao.selectJoinOne(resultType, this));
    }

    /**
     * 链式调用 查询列表第一个 匹配多个不会抛异常
     * <p>
     * 构造方法必须传 class 或 entity 否则会报错<br />
     * new MPJLambdaWrapper(User.class)<br />
     * JoinWrappers.lambda(User.class)<br />
     */
//    public T first() {
//        List<T> list = this.isResultMapCollection() ? list() :
//                page(DefaultPageRequest.of(0, 1, false)).getList();
//        return Optional.of(list).filter(CollectionUtil::isNotEmpty).map(m -> m.get(0)).orElse(null);
//    }

    /**
     * 链式调用 查询列表第一个 匹配多个不会抛异常
     * <p>
     * 构造方法必须传 class 或 entity 否则会报错<br />
     * new MPJLambdaWrapper(User.class)<br />
     * JoinWrappers.lambda(User.class)<br />
     */
//    public <R> R first(Class<R> resultType) {
//        List<R> list = this.isResultMapCollection() ? list(resultType) :
//                page(DefaultPageRequest.of(0, 1, false), resultType).getList();
//        return Optional.of(list).filter(CollectionUtil::isNotEmpty).map(m -> m.get(0)).orElse(null);
//    }

    /**
     * 链式调用
     * 构造方法必须传 class 或 entity 否则会报错<br />
     * new MPJLambdaWrapper(User.class)<br />
     * JoinWrappers.lambda(User.class)<br />
     */
    public List<T> list() {
        return SqlHelper.execute(getEntityClass(), dao -> dao.selectJoinList(getEntityClass(), this));
    }

    /**
     * 链式调用
     * 构造方法必须传 class 或 entity 否则会报错<br />
     * new MPJLambdaWrapper(User.class)<br />
     * JoinWrappers.lambda(User.class)<br />
     */
    public <R> List<R> list(Class<R> resultType) {
        return SqlHelper.execute(getEntityClass(), dao -> dao.selectJoinList(resultType, this));
    }

    /**
     * 链式调用
     * 构造方法必须传 class 或 entity 否则会报错<br />
     * new MPJLambdaWrapper(User.class)<br />
     * JoinWrappers.lambda(User.class)<br />
     */
//    public <P extends PageRequest> PageResult page(P page) {
//        return SqlHelper.execute(getEntityClass(), dao -> dao.selectJoinPage(page, getEntityClass(), this));
//    }

    /**
     * 链式调用
     * 构造方法必须传 class 或 entity 否则会报错<br />
     * new MPJLambdaWrapper(User.class)<br />
     * JoinWrappers.lambda(User.class)<br />
     */
//    public <R, P extends PageRequest> PageResult page(P page, Class<R> resultType) {
//        return SqlHelper.execute(getEntityClass(), dao -> dao.selectJoinPage(page, resultType, this));
//    }

    /**
     * 链式调用
     * 构造方法必须传 class 或 entity 否则会报错<br />
     * new MPJLambdaWrapper(User.class)<br />
     * JoinWrappers.lambda(User.class)<br />
     */
//    public Map<String, Object> mapOne() {
//        return SqlHelper.execute(getEntityClass(), dao -> dao.selectJoinMap(this));
//    }

    /**
     * 链式调用
     * 构造方法必须传 class 或 entity 否则会报错<br />
     * new MPJLambdaWrapper(User.class)<br />
     * JoinWrappers.lambda(User.class)<br />
     */
//    public Map<String, Object> mapFirst() {
//        List<Map<String, Object>> mapList = mapPage(DefaultPageRequest.of(0, 1, false)).getList();
//        return Optional.of(mapList).filter(CollectionUtil::isNotEmpty).map(m -> m.get(0)).orElse(null);
//    }

    /**
     * 链式调用
     * 构造方法必须传 class 或 entity 否则会报错<br />
     * new MPJLambdaWrapper(User.class)<br />
     * JoinWrappers.lambda(User.class)<br />
     */
//    public List<Map<String, Object>> mapList() {
//        return SqlHelper.execute(getEntityClass(), dao -> dao.selectJoinMaps(this));
//    }

    /**
     * 链式调用
     * 构造方法必须传 class 或 entity 否则会报错<br />
     * new MPJLambdaWrapper(User.class)<br />
     * JoinWrappers.lambda(User.class)<br />
     */
//    public <P extends PageRequest<Map>> PageResult mapPage(P page) {
//        return SqlHelper.execute(getEntityClass(), dao -> dao.selectJoinMapsPage(page, this));
//    }
    public int deleteJoin() {
        return SqlHelper.execute(getEntityClass(), mapper -> mapper.deleteJoin(this));
    }

    /**
     * 链式调用
     * <p>
     * 构造方法必须传 class 或 entity 否则会报错 <br />
     * new UpdateJoinWrapper(User.class)<br />
     * JoinWrappers.update(User.class)<br />
     */
//    public int update() {
//        return SqlHelper.execute(getEntityClass(), dao -> dao.updateJoin(null, this));
//    }

    /**
     * 链式调用
     * <p>
     * 构造方法必须传 class 或 entity 否则会报错 <br />
     * new UpdateJoinWrapper(User.class)<br />
     * JoinWrappers.update(User.class)<br />
     */
//    public int update(T entity) {
//        return SqlHelper.execute(getEntityClass(), dao -> dao.updateJoin(entity, this));
//    }

    /**
     * 链式调用
     * <p>
     * 构造方法必须传 class 或 entity 否则会报错 <br />
     * new UpdateJoinWrapper(User.class)<br />
     * JoinWrappers.update(User.class)<br />
     */
//    public int updateAndNull() {
//        return SqlHelper.execute(getEntityClass(), dao -> dao.updateJoinAndNull(null, this));
//    }

    /**
     * 链式调用
     * <p>
     * 构造方法必须传 class 或 entity 否则会报错 <br />
     * new UpdateJoinWrapper(User.class)<br />
     * JoinWrappers.update(User.class)<br />
     */
//    public int updateAndNull(T entity) {
//        return SqlHelper.execute(getEntityClass(), dao -> dao.updateJoinAndNull(entity, this));
//    }

}
